﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using NUnit.Framework.Constraints;

namespace TimScripts.BF4Rcon.Test
{
    [TestFixture]
    public class MapCollectionTests
    {
        MapRconClient Client;
        MapCollection Maps;

        [SetUp]
        public void SetUp()
        {
            Client = new MapRconClient();
            Maps = new MapCollection(Client);
            Client.IsLoggedOn = true;
        }

        [Test]
        public void SingleResponseReadCorrectly()
        {
            Client.AddMap(MapName.HainanResort, GameMode.Rush, 5).
                   AddMap(MapName.GolmudRailway, GameMode.Domination, 7).
                   AddMap(MapName.DragonPass, GameMode.Defuse, 33).
                   Finish();

            Assert.That(Maps, Is.EqualTo(Client.AllMaps).Using(new MapComparer()));
        }

        [Test]
        public void SplitResponseReadCorrectly()
        {
            Client.AddMap(MapName.HainanResort, GameMode.Rush, 5).BeginNewResponse().
                   AddMap(MapName.GolmudRailway, GameMode.Domination, 7).BeginNewResponse().
                   AddMap(MapName.DragonPass, GameMode.Defuse, 33).
                   Finish();

            Assert.That(Maps, Is.EqualTo(Client.AllMaps).Using(new MapComparer()));
        }

        [Test]
        public void AddSendsCorrectData()
        {
            Map map = new Map(MapName.DawnBreaker, GameMode.Domination, 42);

            Maps.Add(map);

            Assert.That(map, Is.EqualTo(Maps[0]).Using(new MapComparer()));
        }

        [Test]
        public void AddingUnknownModeOrMapThrows()
        {
            Map unknownMap = new Map(MapName.Unknown, GameMode.AirSuperiority);
            Map unknownMode = new Map(MapName.SilkRoad, GameMode.Unknown);

            Assert.Throws<UnknownMapNameException>(() => Maps.Add(unknownMap));
            Assert.Throws<UnknownGameModeException>(() => Maps.Add(unknownMode));
        }

        [Test]
        public void AddingWithInvalidRoundsSetsRoundsToOne()
        {
            //as of writing this test, map throws when specified rounds is below one (but allows unspecified -> -1)
            Map noRoundMap = new Map(MapName.SiegeOfShanghai, GameMode.TeamDeathmatch);

            Maps.Add(noRoundMap);

            Assert.AreEqual(1, Maps[0].RoundsToPlay);
        }

        [Test]
        public void InsertSendsCorrectData()
        {
            Map map = new Map(MapName.DawnBreaker, GameMode.Domination, 42);

            Maps.Add(new Map(MapName.SiegeOfShanghai, GameMode.SquadDeathmatch));
            Maps.Insert(0, map);

            Assert.That(map, Is.EqualTo(Maps[0]).Using(new MapComparer()));
        }

        [Test]
        public void InsertingUnknownModeOrMapThrows()
        {
            Map unknownMap = new Map(MapName.Unknown, GameMode.AirSuperiority);
            Map unknownMode = new Map(MapName.SilkRoad, GameMode.Unknown);

            Assert.Throws<UnknownMapNameException>(() => Maps.Add(unknownMap));
            Assert.Throws<UnknownGameModeException>(() => Maps.Add(unknownMode));
        }

        [Test]
        public void InsertingWithInvalidRoundsSetsRoundsToOne()
        {
            //as of writing this test, map throws when specified rounds is below one (but allows unspecified -> -1)
            Map noRoundMap = new Map(MapName.SiegeOfShanghai, GameMode.TeamDeathmatch);

            Maps.Insert(0, noRoundMap);

            Assert.AreEqual(1, Maps[0].RoundsToPlay);
        }

        [Test]
        public void RemoveAtSendsCorrectData()
        {
            Maps.Add(new Map(MapName.SiegeOfShanghai, GameMode.SquadDeathmatch));
            Maps.RemoveAt(0);

            Assert.AreEqual(0, Maps.Count);
        }

        [Test]
        public void IndexerSetRemovesAndInsertsMap()
        {
            Map map = new Map(MapName.DragonPass, GameMode.TeamDeathmatch);
            Client.AddMap(MapName.SiegeOfShanghai, GameMode.Rush, 3).AddMap(MapName.LancangDam, GameMode.Defuse, 7);

            Maps[1] = map;

            Assert.That(map, Is.EqualTo(Maps[1]).Using(new MapComparer().IgnoreRounds()));
        }

        [Test]
        public void CountRequiresLogOn()
        {
            Client.IsLoggedOn = false;

            Assert.Throws<NotLoggedOnException>(() => { var x = Maps.Count; });
        }

        [Test]
        public void EnumerationRequiresLogOn()
        {
            Client.IsLoggedOn = false;
            Assert.Throws<NotLoggedOnException>(() => Maps.ElementAt(0));
        }

        [Test]
        public void IndexerGetRequiresLogOn()
        {
            Client.IsLoggedOn = false;
            Assert.Throws<NotLoggedOnException>(() => { var x = Maps[0]; });
        }

        [Test]
        public void IndexerSetRequiresLogOn()
        {
            Client.IsLoggedOn = false;
            Assert.Throws<NotLoggedOnException>(() => { Maps[0] = new Map(MapName.AltaiRange, GameMode.AirSuperiority); });
        }

        [Test]
        public void AddRequiresLogOn()
        {
            Client.IsLoggedOn = false;
            Assert.Throws<NotLoggedOnException>(() => { Maps.Add(new Map(MapName.AltaiRange, GameMode.AirSuperiority)); });
        }

        [Test]
        public void RemoveAtRequiresLogOn()
        {
            Client.IsLoggedOn = false;

            Assert.Throws<NotLoggedOnException>(() => { Maps.RemoveAt(0); });
        }
    }
}
